// render.h : contains the definition of the render component. This component
// is responsible for rendering the object and displaying it when called for
//$Id: Render.cpp 46 2009-09-24 22:38:34Z brwarner2 $

#include "StdAfx.h"
#include "Render.h"
#include "ResourceManager.h"
#include "Messages.h"
#include "Entity.h"
#include "ObjectManager.h"
#include "GameMonkey.h"

using bug::render::INVALID_POINTER;

CRender::CRender(void) : m_skin(INVALID_POINTER), m_nNumFrames(1), m_nFrameSize(100), m_nCurrentFrame(0), m_fLastFrame(0.0f), m_nFPS(1),
	m_imageInfo()
{
}

CRender::~CRender(void)
{
	//Release skin
	if(m_skin != INVALID_POINTER)
	{
		Resource()->ReleaseSkin(m_skin);
		m_skin = INVALID_POINTER;
	}
}

void CRender::Init(const ParameterList &params)
{
	//Texture load block
	do
	{
		//Check if texture data exists
		if( params.find("texture") == params.end() ) break;

		//Load it
		m_skin = Resource()->CreateTexture( params.find("texture")->second );

		//Load the information file
		LoadInfoFile(params.find("texture")->second + ".info");
	}while(false);
}

float CRender::GetImageInformation( const std::string& name )
{
	if( name == "width" )
	{
		return (float)m_nFrameSize;
	}
	else if( name == "height" )
	{
		return (float)m_nFrameHeight;
	}
	else if( m_imageInfo.find(name) != m_imageInfo.end() )
	{
		return boost::lexical_cast<float>(m_imageInfo[name]);
	}
	else return std::numeric_limits<float>::max();
}

void CRender::LoadInfoFile( const std::string& filename )
{
	std::fstream info = Resource()->File( filename, std::ios_base::in );
	using namespace std;
	string line;
	while(getline(info, line))
	{
		stringstream str = stringstream(line);
		string name;
		getline(str,name, ':');
		unsigned int value;
		str >> value;

		if(name == "frames") m_nNumFrames = value;
		else if(name == "frame-size") m_nFrameSize = value;
		else if(name == "frame-rate") m_nFPS = value;
		else if(name == "height") m_nFrameHeight = value;
		else m_imageInfo[name] = value;
	}
}

void CRender::Message(MessageID message, const boost::any &arg)
{
	using namespace Messages;

	//Check message
	switch(message)
	{
	case Render:
		{
			bug::math::CVector pos = GetEntity()->Position();
			RECT rc;// = Resource()->GetTextureManager()->GetRect( Resource()->GetTextureManager()->GetTexture(m_skin,0) );
			rc.left = m_nCurrentFrame*m_nFrameSize;
			rc.right = rc.left + m_nFrameSize;
			rc.top = 0;
			rc.bottom = m_nFrameHeight;
			Resource()->GetSprite()->Draw( m_skin, pos.m_x, pos.m_z, m_nFrameSize, rc.bottom, rc );
			GetObjectManager()->CallHook(GetObjectID(), "Render");
		}break;
	case Update:
		{
			//Do nothing if we are paused
			if(!m_bPlaying) break;

			//Get elapsed time
			float fElapsed = boost::any_cast<float>(arg);

			//Add to frame time
			m_fLastFrame += fElapsed;

			//Check how many frames have passed since the last frame change
			unsigned int pastFrames = (unsigned int)(m_fLastFrame*(float)m_nFPS);
			if(pastFrames > 0) {
				//Increment current frame
				m_nCurrentFrame += pastFrames;

				//Keep it within bounds
				if(m_nCurrentFrame >= m_nNumFrames) m_nCurrentFrame = m_nCurrentFrame%m_nNumFrames;

				//Reset counter
				m_fLastFrame = 0.0f; //TODO: Make more accurate by including time that is leftover after pastFrames have been added
			}
		}break;
	}
}

int CRender::GMCall( gmThread* a_thread, const std::string &name )
{
	//Get the name of the function
	if( name == "Play" )
	{
		GM_CHECK_NUM_PARAMS(0);
		m_bPlaying = true;
		//m_fLastFrame = 0.0f;
		return GM_OK;
	}
	else if(name == "Pause")
	{
		GM_CHECK_NUM_PARAMS(0);
		m_bPlaying = false;
		return GM_OK;
	}
	else if(name == "SetSprite")
	{
		GM_CHECK_NUM_PARAMS(1);
		GM_CHECK_STRING_PARAM( sprite, 0 );

		//Load it
		m_skin = Resource()->CreateTexture( sprite );

		//Load the information file
		LoadInfoFile(std::string(sprite) + ".info");

		return GM_OK;
	}
	else if(name == "GetWidth")
	{
		GM_CHECK_NUM_PARAMS(0);
		a_thread->PushInt((int)GetImageInformation("width"));
		return GM_OK;
	}
	else if(name == "GetHeight")
	{
		GM_CHECK_NUM_PARAMS(0);
		a_thread->PushInt((int)GetImageInformation("height"));
		return GM_OK;
	}
	return GM_EXCEPTION;
}

void CRender::RegisterGM( gmMachine* pGM )
{
	//Get object manager
	CObjectManager* pObjects = GetGlobalObjectManager(*pGM);
	pObjects->RegisterMemberFunction(COMPONENT_ID, "SetSprite");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "Play");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "Pause");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "GetWidth");
	pObjects->RegisterMemberFunction(COMPONENT_ID, "GetHeight");
}